package com.ys.code.generator.core.create.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ys.code.generator.core.create.ICreateCodeService;
import com.ys.code.generator.core.jdbc.ColumnField;
import com.ys.code.generator.core.jdbc.FileList;
import com.ys.code.generator.core.jdbc.JdbcTypeNameTranslator;
import com.ys.code.generator.core.vo.BaseInfo;
import com.ys.code.generator.core.vo.CodeVo;
import com.ys.code.generator.util.DateUtil;
import com.ys.code.generator.util.DeleteFileUtil;
import com.ys.code.generator.util.FileUtil;
import com.ys.code.generator.util.JdbcUtil;
import com.ys.code.generator.util.PropertiesUtil;
import com.ys.code.generator.util.TemplateUtil;
import com.ys.code.generator.util.ZipUtils;

@Service
public class CreateCodeServiceImpl implements ICreateCodeService {
	@Autowired
	private TemplateUtil templateUtil;

	@Override
	public void createCode(List<CodeVo> datas,String db,OutputStream outputStream) throws Exception {
		String rootPath = FileUtil.getClassPath() + "target/";
		File file = new File(rootPath);
		if(file.exists() && file.listFiles()!=null) {
			//清除上一次的文件
			DeleteFileUtil.deleteDirectory(rootPath);
		}
		
		List<BaseInfo> baseInfoList = getBaseInfos(datas,db);
		List<FileBean> fileList = new ArrayList<CreateCodeServiceImpl.FileBean>();
		int i = 1;
		if(baseInfoList!=null && baseInfoList.size()>0) {
			for (BaseInfo baseInfo : baseInfoList) {
				Map<String, String> map = FileList.getFileToPath(baseInfo);
				baseInfo.setPrimaryKeyMergerFLower(StringUtils.uncapitalize(baseInfo.getPrimaryKeyMerger())); // 主键合并后首字母小写
				for (Iterator<Entry<String, String>> localIterator = map.entrySet().iterator(); localIterator.hasNext();) {
					Map.Entry<String,String> entry = (Map.Entry<String,String>) localIterator.next();
					String context = templateUtil.getText((String) entry.getKey(), baseInfo); // 生成模版
					String filePath = rootPath + ((String) entry.getValue());
					FileUtil.string2File(context, filePath);
					fileList.add(new FileBean(i, filePath));
					i++;
				}
			}
			ZipOutputStream out = new ZipOutputStream(outputStream);
			try {
				ZipUtils.doCompress(new File(rootPath), out);
				outputStream.flush();
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				out.close();
			}
		}
	}

	//文件类
	class FileBean implements Serializable {
		private static final long serialVersionUID = -5452801884470115159L;
		private Integer fileId;// 主键
		private String filePath;// 文件保存路径

		public FileBean(Integer fileId, String filePath) {
			this.fileId = fileId;
			this.filePath = filePath;
		}

		public Integer getFileId() {
			return fileId;
		}

		public void setFileId(Integer fileId) {
			this.fileId = fileId;
		}

		public String getFilePath() {
			return filePath;
		}

		public void setFilePath(String filePath) {
			this.filePath = filePath;
		}
	}

	public List<BaseInfo> getBaseInfos(List<CodeVo> datas,String db) throws Exception {
		List<BaseInfo> baseInfoList = new ArrayList<BaseInfo>();
		String driver = PropertiesUtil.getProperties("jdbc.driver");
		String url = PropertiesUtil.getProperties("jdbc.url")+"/"+db;
		String userName = PropertiesUtil.getProperties("jdbc.userName");
		String password = PropertiesUtil.getProperties("jdbc.password");


		// String[]
		// parameters=PropertiesUtil.getProperties("parameters").split(",");
		// String[]
		// templates=PropertiesUtil.getProperties("templates").split(",");

		if (null != driver) {
			if (null != datas) {
				for (CodeVo vo : datas) {
					BaseInfo baseInfo = new BaseInfo();
					// 1:设置数据源
					baseInfo.setDriver(driver.trim());
					baseInfo.setUrl(url.trim());
					baseInfo.setUserName(userName.trim());
					baseInfo.setPassword(password.trim());

					// 2：设置表
					baseInfo.setTableName(vo.getTableName().trim());
					if (StringUtils.isNotBlank(vo.getPrimaryKey())) {
						baseInfo.setPrimaryKeyMerger(vo.getPrimaryKey().trim());
					}
					if (StringUtils.isNotBlank(vo.getAuthor())) {
						baseInfo.setAuthor(vo.getAuthor().trim());
					}

					if (StringUtils.isNotBlank(vo.getCompanyName())) {
						baseInfo.setCompanyName(vo.getCompanyName().trim());
					}

					if (StringUtils.isNotBlank(vo.getProjectName())) {
						baseInfo.setProjectName(vo.getProjectName().trim());
					}

					if (StringUtils.isNotBlank(vo.getModel())) {
						baseInfo.setModel(vo.getModel().trim());
					}

					if (StringUtils.isNotBlank(vo.getObjectNameCn())) {
						baseInfo.setObjectNameCn(vo.getObjectNameCn().trim());
					}

					if (StringUtils.isNotBlank(vo.getAbbObjectName())) {
						baseInfo.setAbbObjectName(vo.getAbbObjectName().trim());
					}
					if (StringUtils.isNotBlank(vo.getObjectName())) {
						baseInfo.setObjectName(vo.getObjectName().trim());
					}
					
					if (StringUtils.isNotBlank(vo.getfLowerObjectName())) {
						baseInfo.setfLowerObjectName(vo.getfLowerObjectName().trim());
					}

					// 设置自定义的参数和自定义的模板
					// if (!ArrayUtils.isEmpty(parameters) && parameters.length
					// > i && StringUtils.isNotBlank(parameters[i])) {
					// baseInfo.setParameters(this.getMapInfo(parameters[i].trim()));
					// }
					// if (!ArrayUtils.isEmpty(templates) && templates.length >
					// i && StringUtils.isNotBlank(templates[i])) {
					// baseInfo.setTemplates(this.getMapInfo(templates[i].trim()));
					// }
					baseInfoList.add(baseInfo);
				}
			}
		}
		return this.getBaseInfoList(baseInfoList);
	}

	public List<BaseInfo> getBaseInfoList(List<BaseInfo> baseInfoList) throws Exception {
		Connection connection = null;
		try {
			for (BaseInfo baseInfo : baseInfoList) {
				String driver = baseInfo.getDriver();
				String url = baseInfo.getUrl();
				String userName = baseInfo.getUserName();
				String password = baseInfo.getPassword();
				String tableName = baseInfo.getTableName();

				connection = JdbcUtil.getConnection(driver, url, userName, password);
				Statement statement = connection.createStatement();

				ResultSet rs = statement.executeQuery("select * from " + tableName + " where 1=2");

				Map<String, String> columnCommentMap = getColumnComment(connection, tableName);

				ResultSetMetaData rsmd = rs.getMetaData();

				List<ColumnField> columnFieldList = new ArrayList<ColumnField>();

				int count = rsmd.getColumnCount();

				for (int i = 1; i <= count; ++i) {
					String columnName = rsmd.getColumnName(i);
					int jdbcType = rsmd.getColumnType(i);
					ColumnField columnField = new ColumnField();
					String field = getField(columnName);
					String cField = StringUtils.capitalize(field);

					columnField.setColumn(columnName);
					columnField.setField(field);
					columnField.setcField(cField);
					columnField.setJdbcType(JdbcTypeNameTranslator.getJdbcTypeName(jdbcType));
					columnField.setJavaType(JdbcTypeNameTranslator.getJavaType(jdbcType));
					columnField.setComment((String) columnCommentMap.get(columnName));

					columnFieldList.add(columnField);
				}
				baseInfo.setColumnFieldList(columnFieldList);
				baseInfo.setCreateTime(DateUtil.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss"));

				// 取得主键信息
				DatabaseMetaData dbMeta = connection.getMetaData();
				ResultSet primaryKeys = dbMeta.getPrimaryKeys(null, null, tableName);
				StringBuffer primaryKeysSbf = new StringBuffer();

				List<String> primaryKeysList = new ArrayList<String>();
				int i = 0;
				while (primaryKeys.next()) {
					System.err.println("****** Comment ******");
					System.err.println("[数据库名]TABLE_CAT : " + primaryKeys.getObject(1));
					System.err.println("[]TABLE_SCHEM: " + primaryKeys.getObject(2));
					System.err.println("[表名称]TABLE_NAME : " + primaryKeys.getObject(3));
					System.err.println("[主键名称]COLUMN_NAME: " + primaryKeys.getObject(4));
					System.err.println("[主键的顺序位置]KEY_SEQ : " + primaryKeys.getObject(5));
					System.err.println("[]PK_NAME : " + primaryKeys.getObject(6));
					System.err.println("****** ******* ******");
					primaryKeysList.add((String) primaryKeys.getObject(4));
					i++;
					primaryKeysSbf.append(primaryKeys.getObject(4)).append(",");
				}

				System.err.println(primaryKeysSbf.toString());
				System.err.println(this.setPrimaryKeysFromArray(primaryKeysSbf.toString().split(","), baseInfo));

				baseInfo.setPrimaryKeys(primaryKeysList.toArray(new String[primaryKeysList.size()]));
				String st = this.setPrimaryKeysFromArray(primaryKeysSbf.toString().split(","), baseInfo);
				if (StringUtils.isBlank(baseInfo.getPrimaryKeyMerger())) {
					baseInfo.setPrimaryKeyMerger(st);
				} else {
					System.err.println(baseInfo.getPrimaryKeyMerger());
				}

			}
		} catch (Exception e) {
		} finally {
			if (connection != null) {
				connection.close();
			}
			// throw localObject;
			if (connection == null)
				return baseInfoList;
		}
		connection.close();

		label358: return baseInfoList;
	}

	/**
	 * 组合主键：如果file_id,property_value_id为共同主键，那么组合后的结果为FileIdAndPropertyValueId
	 */
	public String setPrimaryKeysFromArray(String[] strs, BaseInfo baseInfo) { // 数据库中列名的命名规则：如file_id,property_value_id等等，使用“_”分割
		if (null != strs && strs.length > 0) {
			String[] primaryKeysConvert = new String[strs.length];
			StringBuffer sbkeys = new StringBuffer();
			int i = 0;
			for (String str : strs) { // 循环主键
				if (str.indexOf("_") != -1) {
					StringBuffer sbkey = new StringBuffer();
					for (String string : str.split("_")) {
						sbkey.append(StringUtils.capitalize(string.trim())); // 首字母大写
					}
					sbkeys.append(sbkey);
					primaryKeysConvert[i] = StringUtils.uncapitalize(sbkey.toString());
				} else {
					sbkeys.append(StringUtils.capitalize(str.trim()));// 首字母大写
					primaryKeysConvert[i] = StringUtils.uncapitalize(str.trim()); // 首字母小写
				}

				i++;
				if (i < strs.length) {
					sbkeys.append("And");
				}
			}
			baseInfo.setPrimaryKeysConvert(primaryKeysConvert);
			return StringUtils.isNotBlank(sbkeys.toString()) ? sbkeys.toString().trim() : null;

		}
		return null;
	}

	public Map<String, String> getColumnComment(Connection connection, String tableName) throws Exception {
		Map<String, String> map = new HashMap<String, String>();

		Statement statement = connection.createStatement();

		String sql = "SELECT column_name,COLUMN_COMMENT FROM information_schema.COLUMNS WHERE table_name =";
		ResultSet rs = statement.executeQuery(sql + "UPPER('" + tableName + "')");

		if (rs.next()) {
			rs.previous();
		} else {
			rs = statement.executeQuery(sql + "'" + tableName + "'");
		}

		while (rs.next()) {
			String column = rs.getString(1);
			String comments = rs.getString(2);
			map.put(column, comments);
		}

		return map;
	}

	private String getField(String column) {
		String[] columnSplit = column.split("_");

		StringBuffer field = new StringBuffer();

		for (int i = 0; i < columnSplit.length; ++i) {
			if (i != 0) {
				field.append(StringUtils.capitalize(StringUtils.lowerCase(columnSplit[i])));
			} else {
				field.append(StringUtils.uncapitalize(StringUtils.lowerCase(columnSplit[i])));
			}
		}

		return field.toString();
	}

	// 拆分数据封装到map中去
	@SuppressWarnings("unused")
	private Map<String, String> getMapInfo(String paras) {
		Map<String, String> map = null;
		if (StringUtils.isNotBlank(paras)) {
			String[] ps = paras.split("\\$");
			if (!ArrayUtils.isEmpty(ps)) {
				map = new HashMap<String, String>();
				for (String str : ps) {
					if (StringUtils.isNotBlank(str)) {
						String[] array = str.trim().split("\\^");
						if (!ArrayUtils.isEmpty(array) && array.length == 2) {
							map.put(array[0].trim(), array[1].trim());
						}
					}
				}
			}
		}
		return map;
	}
	
	public static void main(String[] args) throws Exception {
		ICreateCodeService createCodeService = new CreateCodeServiceImpl();
		List<CodeVo> datas = new ArrayList<CodeVo>();
		OutputStream outputStream = new FileOutputStream(new File("d://test.zip"));
		
		CodeVo vo = new CodeVo();
		vo.setAbbObjectName("user");
		vo.setAuthor("bruce.liu");
		vo.setCompanyName("ys");
		vo.setfLowerObjectName("user");
		vo.setModel("user");
		vo.setObjectName("User");
		vo.setObjectNameCn("用户");
		vo.setProjectName("privilege");
		vo.setTableName("tbl_privilege_user");
		datas.add(vo);
		createCodeService.createCode(datas, "privilege_b", outputStream);
	}

}
